
#include "n32g45x.h"
#include "board.h"

static uint16_t adc_value[ADC_CHANNEL_NUM - 1] = {0};

/* the other one channel is used for injected channel */
uint16_t adc_ready_value[ADC_CHANNEL_NUM] = {0};

static void _adc1_init(void)
{
    NVIC_InitType NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel                   = DMA1_Channel1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel                   = ADC1_2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    DMA_InitType DMA_InitStructure;
    DMA_DeInit(DMA1_CH1);
    DMA_RequestRemap(DMA1_REMAP_ADC1, DMA1, DMA1_CH1, ENABLE);
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.PeriphAddr     = (uint32_t)&ADC1->DAT;
    DMA_InitStructure.MemAddr        = (uint32_t)adc_value;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_SRC;
    DMA_InitStructure.BufSize        = ADC_CHANNEL_NUM - 1;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.CircularMode   = DMA_MODE_CIRCULAR;
    DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
    DMA_Init(DMA1_CH1, &DMA_InitStructure);
    DMA_ConfigInt(DMA1_CH1, DMA_INT_TXC, ENABLE);
    DMA_EnableChannel(DMA1_CH1, ENABLE);

    ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB,RCC_ADCHCLK_DIV16);
    ADC_InitType ADC_InitStructure;
    ADC_InitStruct(&ADC_InitStructure);
    ADC_InitStructure.WorkMode       = ADC_WORKMODE_INDEPENDENT;
    ADC_InitStructure.MultiChEn      = ENABLE;
    ADC_InitStructure.ContinueConvEn = DISABLE;
    ADC_InitStructure.ExtTrigSelect  = ADC_EXT_TRIGCONV_T1_CC1;
    ADC_InitStructure.DatAlign       = ADC_DAT_ALIGN_R;
    ADC_InitStructure.ChsNumber      = ADC_CHANNEL_NUM - 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    // Regular channel
    ADC_ConfigRegularChannel(ADC1, ADC1_Channel_06_PC0, 1, ADC_SAMP_TIME_71CYCLES5);
    ADC_ConfigRegularChannel(ADC1, ADC1_Channel_07_PC1, 2, ADC_SAMP_TIME_71CYCLES5);
    ADC_ConfigRegularChannel(ADC1, ADC1_Channel_08_PC2, 3, ADC_SAMP_TIME_71CYCLES5);
    ADC_ConfigRegularChannel(ADC1, ADC_CH_16, 4, ADC_SAMP_TIME_71CYCLES5);
    ADC_EnableExternalTrigConv(ADC1, ENABLE);

    // Injected channel
    ADC_ConfigInjectedSequencerLength(ADC1, 1);
    ADC_ConfigInjectedChannel(ADC1, ADC_CH_16, 1, ADC_SAMP_TIME_71CYCLES5);
    ADC_ConfigExternalTrigInjectedConv(ADC1, ADC_EXT_TRIG_INJ_CONV_T1_CC4);
    ADC_EnableExternalTrigInjectedConv(ADC1, ENABLE);
    ADC_ConfigInt(ADC1, ADC_INT_JENDCA, ENABLE);

    ADC_EnableTempSensorVrefint(ENABLE);

    ADC_Enable(ADC1, ENABLE);
    while(ADC_GetFlagStatusNew(ADC1,ADC_FLAG_RDY) == RESET)
    {
    }
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1))
    {
    }
    ADC_EnableDMA(ADC1, ENABLE);

}

void ADC1_2_IRQHandler(void)
{
    if(ADC_GetIntStatus(ADC1, ADC_INT_JENDCA) != RESET)
    {
        ADC_ClearIntPendingBit(ADC1, ADC_INT_JENDCA);
        uint32_t primask = __get_PRIMASK();
        __disable_irq();
        adc_ready_value[ADC_CHANNEL_NUM - 1] = ADC_GetInjectedConversionDat(ADC1, ADC_INJ_CH_1);
        __set_PRIMASK(primask);
    }
}

void DMA1_Channel1_IRQHandler(void)
{
    if (DMA_GetIntStatus(DMA1_INT_TXC1, DMA1) != RESET)
    {
        DMA_ClrIntPendingBit(DMA1_INT_TXC1, DMA1);
        uint32_t primask = __get_PRIMASK();
        __disable_irq();
        for (int i = 0; i < ADC_CHANNEL_NUM - 1; i++)
        {
            adc_ready_value[i] = adc_value[i];
        }
        __set_PRIMASK(primask);
    }
}

static void _timer1_init(void)
{
    TIM_TimeBaseInitType TIM_TimeBaseStructure;
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.Period    = 0x88FF; // 0xFF;
    TIM_TimeBaseStructure.Prescaler = 0x4;
    TIM_TimeBaseStructure.ClkDiv    = 0x0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;
    TIM_InitTimeBase(TIM1, &TIM_TimeBaseStructure);

    OCInitType TIM_OCInitStructure;
    TIM_InitOcStruct(&TIM_OCInitStructure);
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = 0x7F;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;
    TIM_InitOc1(TIM1, &TIM_OCInitStructure);    // for ADC1 Regular channel trigger && pwm output

    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = 0x4FF;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;
    TIM_InitOc4(TIM1, &TIM_OCInitStructure);    // for ADC1 Injected channel trigger

    TIM_Enable(TIM1, ENABLE);
    TIM_EnableCtrlPwmOutputs(TIM1, ENABLE);

}

int driv_timer_adc_init(void)
{
    _timer1_init();
    _adc1_init();
    return 0;
}

int driv_adc_get_value(uint16_t* val)
{
    if (!val) {
        return -1;
    }
    uint32_t primask = __get_PRIMASK();
    __disable_irq();
    for (int i = 0; i < ADC_CHANNEL_NUM; i++)
    {
        val[i] = adc_ready_value[i];
    }
    __set_PRIMASK(primask);

    return 0;
}

int driv_timer_pwm_set(uint16_t pwm_value)
{
    TIM_SetCmp1(TIM1, pwm_value);
    return 0;
}


